package slu.appli.wodtimer.command;

import slu.appli.command.CommandRunnerInterface;
import slu.appli.command.impl.CommandRunner;
import slu.appli.logger.interfaces.LoggerInterface;
import slu.appli.sound.interfaces.SoundPlayerInterface;
import slu.appli.tools.parser.stringparser.interfaces.model.ModelReaderInterface;
import slu.appli.wodtimer.WodTimer;
import slu.appli.wodtimer.WodTimerException;
import slu.appli.wodtimer.WodTimerUIInterface;
import slu.appli.wodtimer.info.WodTimerInformation;
import slu.appli.wodtimer.info.WodTimerInformationListenerInterface;

public class WodTimerUIControler
implements WodTimerUIInterface {
	private final WodTimer wodTimer;
	private final CommandRunnerInterface<WodTimerCommand> runner;
	private SoundPlayerInterface player;
	private ModelReaderInterface reader = null;
	
	private class WodTimerCommandStart extends WodTimerCommand {
		private final String wod;
		private final SoundPlayerInterface player;
		private final LoggerInterface logger;

		public WodTimerCommandStart(String wod,
				SoundPlayerInterface player, LoggerInterface logger) {
			super(WodTimerCommand.CMD_START);
			this.wod = wod;
			this.player = player;
			this.logger = logger;
		}


		@Override
		public void run() {
			if (WodTimerUIControler.this.runner.isCommandRunnerThread()) {
				Thread thread = new Thread(this);
				thread.setDaemon(true);
				thread.start();
			}
			else {
				try {
					WodTimerUIControler.this.wodTimer.processString(wod,
							player);
				} catch (Exception e) {
					this.logger.addException(e);
				}
			}
			
		}
		
	}

	private class WodTimerCommandRestart extends WodTimerCommand {
		private final ModelReaderInterface reader;

		public WodTimerCommandRestart(ModelReaderInterface reader) {
			super(WodTimerCommand.CMD_RESTART);
			this.reader = reader;
		}


		@Override
		public void run() {
			if (WodTimerUIControler.this.runner.isCommandRunnerThread()) {
				Thread thread = new Thread(this);
				thread.setDaemon(true);
				thread.start();
			}
			else {
				if (this.reader != null) this.reader.restart();
			}
			
		}
		
	}

	private class WodTimerCommandPause extends WodTimerCommand {
		private final ModelReaderInterface reader;

		public WodTimerCommandPause(ModelReaderInterface reader) {
			super(WodTimerCommand.CMD_PAUSE);
			this.reader = reader;
		}


		@Override
		public void run() {
			if (this.reader != null) this.reader.pause();
		}
		
	}


	private class WodTimerCommandStop extends WodTimerCommand {
		private final ModelReaderInterface reader;

		public WodTimerCommandStop(ModelReaderInterface reader) {
			super(WodTimerCommand.CMD_STOP);
			this.reader = reader;
		}


		@Override
		public void run() {
			if (this.reader != null) this.reader.stop();
		}
		
	}
	
	private class InnerListener implements WodTimerInformationListenerInterface {

		@Override
		public void WodTimerChanged(WodTimerInformation infos) {
			if (infos.isStart()) {
				WodTimerUIControler.this.reader = infos.getReader();
			}
			else if (infos.isEnd() || infos.isError()) WodTimerUIControler.this.reader = null;
		}
		
	}
	
	public WodTimerUIControler(WodTimer wodTimer) {
		super();
		this.wodTimer = wodTimer;
		this.runner = new CommandRunner<WodTimerCommand>();
		this.wodTimer.addListener(new InnerListener());
	}

	public SoundPlayerInterface getPlayer() {
		return this.player;
	}

	public LoggerInterface getLogger() {
		return this.wodTimer.getLogger();
	}

	public void setPlayer(SoundPlayerInterface player) {
		this.player = player;
	}

	public void setLogger(LoggerInterface logger) {
		this.wodTimer.setLogger(logger);
	}

	@Override
	public void play(String wod) throws WodTimerException {
		if (this.reader != null) throw new WodTimerException();
		this.runner.postCommand(new WodTimerCommandStart(wod, this.player, this.getLogger()));
	}

	@Override
	public void stop() throws WodTimerException {
		if (this.reader == null) throw new WodTimerException();
		this.runner.postCommand(new WodTimerCommandStop(this.reader));
	}

	@Override
	public void pause() throws WodTimerException {
		if (this.reader == null) throw new WodTimerException();
		this.runner.postCommand(new WodTimerCommandPause(this.reader));
	}

	@Override
	public void restart() throws WodTimerException {
		if (this.reader == null) throw new WodTimerException();
		this.runner.postCommand(new WodTimerCommandRestart(this.reader));
	}

	@Override
	public void addWodTimerInformationListener(
			WodTimerInformationListenerInterface listener) {
		this.wodTimer.addListener(listener);
	}

	@Override
	public void removeWodTimerInformationListener(
			WodTimerInformationListenerInterface listener) {
		this.wodTimer.removeListener(listener);
	}

	@Override
	public long calculate(String wod) throws WodTimerException {
		return this.wodTimer.computeDuration(wod);
	}

}
